package com.hubu.thread.lock;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
public class LockChangeStateTest {
    public static void main(String[] args) throws Exception {
        //测试无锁
        test01();
        //测试偏向锁
        test02();
        //测试轻量级锁
        test03();

        //测试由轻量级锁变为重量级锁
        test04();

        //测试由偏向锁到到重量级锁
        test05();

        //测试由偏向锁到偏向锁
        test06();

        //测试由偏向锁到轻量级锁到重量级锁
        test07();
    }
    private static Unsafe getUnsafe() throws Exception {
        Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
        Field field = unsafeClass.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        return  (Unsafe) field.get(null);
    }
    private static void printLockHeader(Object obj) throws Exception {
        Unsafe us = getUnsafe();
        StringBuilder sb = new StringBuilder();
        int status = us.getByte(obj, 0L) & 0B11;
        // 0 轻量级 1 无锁或偏向 2 重量级 3 GC标记
        switch (status){
            case 0:
                // ptr_to_lock_record:62|lock:2
                long ptrToLockRecord =
                        (byteMod(us.getByte(obj, 0L))>>2) +
                                (byteMod(us.getByte(obj, 1L))<<6) +
                                (byteMod(us.getByte(obj, 2L))<<14) +
                                (byteMod(us.getByte(obj, 3L))<<22) +
                                (byteMod(us.getByte(obj, 4L))<<30) +
                                (byteMod(us.getByte(obj, 5L))<<38) +
                                (byteMod(us.getByte(obj, 6L))<<46) +
                                (byteMod(us.getByte(obj, 7L))<<54);
                sb.append("锁状态：轻量级锁，LockRecord地址：")
                        .append(Long.toHexString(ptrToLockRecord))
                ;
                break;
            case 1:
                boolean biased = (us.getByte(obj, 0L)&4) == 4;
                if(!biased){
                    // unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2
                    int hashCode = (int)(byteMod(us.getByte(obj, 1L))
                            + (byteMod(us.getByte(obj, 2L))<<8)
                            + (byteMod(us.getByte(obj, 3L))<<16)
                            + ((byteMod(us.getByte(obj, 4L))&Integer.MAX_VALUE) <<24))
                            ;
                    int age = (us.getByte(obj,0L)>>3)&0B1111;
                    sb.append("锁状态：无锁，hashCode：")
                            .append(hashCode)
                            .append(",age: ")
                            .append(age);
                }else{
                    //thread:54|epoch:2|unused:1| age:4 | biased_lock:1 | lock:2
                    long thread = (byteMod(us.getByte(obj, 1L))>>2) +
                            (byteMod(us.getByte(obj, 2L))<<6) +
                            (byteMod(us.getByte(obj, 3L))<<14) +
                            (byteMod(us.getByte(obj, 4L))<<22) +
                            (byteMod(us.getByte(obj, 5L))<<30) +
                            (byteMod(us.getByte(obj, 6L))<<38) +
                            (byteMod(us.getByte(obj, 7L))<<46);
                    ;
                    int epoch = us.getByte(obj, 1L) & 0B11;
                    int age = (us.getByte(obj,0L)>>3)&0B1111;
                    sb.append("锁状态：偏向锁，thread：")
                            .append(thread)
                            .append(",epoch: ")
                            .append(epoch)
                            .append(",age: ")
                            .append(age);
                }
                break;
            case 2:
                // ptr_to_heavyweight_monitor:62| lock:2
                long ptrToMonitor =
                        (byteMod(us.getByte(obj, 0L))>>2) +
                                (byteMod(us.getByte(obj, 1L))<<6) +
                                (byteMod(us.getByte(obj, 2L))<<14) +
                                (byteMod(us.getByte(obj, 3L))<<22) +
                                (byteMod(us.getByte(obj, 4L))<<30) +
                                (byteMod(us.getByte(obj, 5L))<<38) +
                                (byteMod(us.getByte(obj, 6L))<<46) +
                                (byteMod(us.getByte(obj, 7L))<<54);
                sb.append("锁状态：重量级锁，Monitor地址：")
                        .append(Long.toHexString(ptrToMonitor))
                ;
                break;
            case 3:
                sb.append("锁状态：GC标记");
                break;
            default:
                break;
        }
        if(obj instanceof Object[]){
            int arrLen = us.getInt(obj, 3L);
            sb.append("对象为数组类型，数组长度:")
                    .append(arrLen);
        }
        sb.append("\n").append("---------------").append("\n");
        System.out.println(sb.toString());
    }
    private static long byteMod(byte b){
        if(b>=0){
            return b;
        }
        return b + 256;
    }


    //测试偏向锁
    public static void test01(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o=new Object();
        try {
            printLockHeader(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     *
     * 测试偏向锁
     */
    public static void test02(){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o=new Object();
        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //程序不预热，加了synchronized 一上来就是轻量级锁
    public static void test03(){
        Object o=new Object();
        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("释放锁之后");
        new Thread(()->{
            synchronized (o){
                try {
                    printLockHeader(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


    /**
     *
     * 测试由轻量级锁变为重量级锁
     */
    public static void test04(){
        Object o=new Object();
        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("轻量级锁释放成功之后");

        //触发竞争条件
        Thread t1 = new Thread(() -> {
            synchronized (o){
                try {
                    //成功获取到锁得线程先随眠1000ms
                    Thread.sleep(1000);
                    printLockHeader(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            synchronized (o){
                try {
                    Thread.sleep(1000);
                    printLockHeader(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "t2");

        t1.start();
        t2.start();
    }


    //测试由偏向锁到重量级锁
    public static void test05(){

        System.out.println("由偏向锁到重量级锁");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o=new Object();
        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        System.out.println("轻量级锁");

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
    //测试由偏向锁到偏向锁
    public static void test06(){
        System.out.println("由偏向锁到偏向锁");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o=new Object();


        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //测试由偏向锁到轻量级锁到重量级锁
    public static void test07(){
        System.out.println("偏向锁到轻量级锁到重量级锁");
        //偏向锁部分
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o=new Object();
        synchronized (o){
            try {
                printLockHeader(o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        //轻量级锁
        Thread t1 = new Thread(() -> {
            synchronized (o) {
                try {
                    printLockHeader(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread t2= new Thread(() -> {
            synchronized (o) {
                try {
                    Thread.sleep(1000);
                    printLockHeader(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t3= new Thread(() -> {
            synchronized (o) {
                try {
                    Thread.sleep(1000);
                    printLockHeader(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        t2.start();
        t3.start();
    }
}
